package com.ruoyi.system.service.impl;

import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.system.domain.SysThird;
import com.ruoyi.system.ldap.SSLLdapContextSource;
import com.ruoyi.system.service.ILdapService;
import com.ruoyi.system.service.ISysThirdService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.NamingException;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.DefaultTlsDirContextAuthenticationStrategy;
import org.springframework.ldap.core.support.DirContextAuthenticationStrategy;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.ldap.query.LdapQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

/**
 * @author renzhihao
 * @date 2023/12/06 15:13
 */
@Service
public class ILdapServiceImpl implements ILdapService {
    private static final Logger log = LoggerFactory.getLogger(ILdapServiceImpl.class);

    public static final String TRANSPORT_TYPE_CLEAR = "1";
    public static final String TRANSPORT_TYPE_LDAPS = "2";
    public static final String TRANSPORT_TYPE_STARTTLS = "3";

    @Autowired
    private ISysThirdService sysThirdService;

    @Override
    public void authenticate(String account, String password) {
        SysThird sysThird = sysThirdService.selectThirdAuth();

        String objectClass = sysThird.getObjectClass();

        LdapTemplate ldapTemplate = getLdapTemplate(sysThird);
        String attr = objectClass.substring(objectClass.lastIndexOf(',') + 1);
        try {
            LdapQuery query = LdapQueryBuilder.query().where(sysThird.getAccountAttr())
                    .is(account).and("objectClass").is(attr);
            ldapTemplate.authenticate(query, password);
        } catch (NamingException e) {
            log.error("ldap认证失败", e);
            throw new UserPasswordNotMatchException(e.getExplanation());
        } catch (Exception e) {
            log.error("ldap认证失败", e);
            throw new UserPasswordNotMatchException(e.getMessage());
        }
    }

    private LdapTemplate getLdapTemplate(SysThird sysThird) {
        String scheme = sysThird.getLdapScheme();
        String host = sysThird.getLdapIp();
        int port = sysThird.getLdapPort();

        String baseDn = sysThird.getBaseDn();
        String username = sysThird.getUsername();
        String password = sysThird.getPassword();

        final LdapTemplate ldapTemplate;
        LdapContextSource contextSource = new LdapContextSource();

        if (TRANSPORT_TYPE_CLEAR.equals(scheme)) {
            scheme = "ldap";
        } else if (TRANSPORT_TYPE_LDAPS.equals(scheme)) {
            scheme = "ldaps";
            contextSource = new SSLLdapContextSource();
        } else if (TRANSPORT_TYPE_STARTTLS.equals(scheme)) {
            scheme = "ldap";
            DirContextAuthenticationStrategy authStrategy = new DefaultTlsDirContextAuthenticationStrategy();
            contextSource.setAuthenticationStrategy(authStrategy);
        }

        String ldapUrl = UriComponentsBuilder.newInstance().scheme(scheme).host(host).port(port).toUriString();

        contextSource.setUrl(ldapUrl);
        contextSource.setBase(baseDn);
        contextSource.setUserDn(username);
        contextSource.setPassword(password);
        contextSource.setPooled(false);
        contextSource.setAnonymousReadOnly(false);
        contextSource.afterPropertiesSet();


        ldapTemplate = new LdapTemplate(contextSource);
        return ldapTemplate;
    }
}
